package com.example.shop.user.controller;

import com.example.shop.common.api.ResponseResult;
import com.example.shop.common.api.ServiceReturn;
import com.example.shop.common.api.ServiceStateCode;
import com.example.shop.common.api.StateCode;
import com.example.shop.common.enums.SessionAttributeKey;
import com.example.shop.common.util.CachedThreadPoolUtil;
import com.example.shop.goods.dto.*;

import com.example.shop.goods.service.BrowseEvaluationService;
import com.example.shop.goods.service.BrowseGoodsService;
import com.example.shop.goods.service.EvaluationService;

import com.example.shop.logistics.service.LogisticsService;
import com.example.shop.order.service.WXNativePayService;
import com.example.shop.pojo.User;
import com.example.shop.redis.enums.RedisKey;
import com.example.shop.redis.service.LettuceClient;
import com.example.shop.user.vo.BuyResult;
import com.example.shop.user.dto.GoodsBuyInfo;
import com.example.shop.user.service.BrowsingHistoryService;
import com.example.shop.user.service.BuyGoodsService;
import com.example.shop.user.service.GoodsCollectionService;
import com.example.shop.user.vo.GoodsDetailBrowseInfoView;
import com.example.shop.user.websocket.InformWebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;

import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpSession;
import javax.validation.constraints.NotNull;

import java.util.*;

import java.util.concurrent.Future;

@RestController
@RequestMapping("/user/goods")
public class GoodsController {

    @Autowired
    EvaluationService evaluationService;
    @Autowired
    BrowseEvaluationService browseEvaluationService;
    @Autowired
    BrowseGoodsService browseGoodsService;
    @Autowired
    BrowsingHistoryService browsingHistoryService;
    @Autowired
    GoodsCollectionService goodsCollectionService;
    @Autowired
    LettuceClient redisClient;
    @Autowired
    WXNativePayService wxNativePayService;
    @Autowired
    BuyGoodsService buyGoodsService;
    @Autowired
    LogisticsService logisticsService;

    @GetMapping("/confirm/{orderId}")
    public ResponseResult<Boolean> confirmGoods(HttpSession session,@PathVariable("orderId")long orderId){
        User user = (User) session.getAttribute(SessionAttributeKey.NOW_LOGIN_USER.getKey());
        ServiceReturn<Boolean> result = logisticsService.ConfirmGoods(user, orderId);
        return ResponseResult.auto(result.getStateCode(),result.getReturnData());
    }

    @GetMapping(value = {"/buy/success/{orderId}/{webSocketSessionId}","/buy/success/{orderId}"})
    public ResponseResult<Boolean> buySuccessCallback(HttpSession session,@PathVariable("orderId") Long orderId,@PathVariable(value = "webSocketSessionId",required = false)String webSocketSessionId){
        InformWebSocketServer socketServer = null;
        if(webSocketSessionId!=null){
            socketServer = InformWebSocketServer.getWebSocketServer(webSocketSessionId);
        }
        ServiceReturn<Boolean> result = buyGoodsService.buySuccess(orderId, socketServer);
        return ResponseResult.success(result.getReturnData());
    }

    @PostMapping("/buy")
    public ResponseResult<BuyResult> buyGoods(HttpSession session,@Validated GoodsBuyInfo buyInfo, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            return ResponseResult.failure(ServiceStateCode.PARAMETER_NONSTANDARD);
        }
        User user = (User) session.getAttribute(SessionAttributeKey.NOW_LOGIN_USER.getKey());
        String webSocketSessionId = (String) session.getAttribute(SessionAttributeKey.INFORM_SESSION_ID.getKey());
        ServiceReturn<BuyResult> result = buyGoodsService.buyGoods(user, buyInfo,webSocketSessionId);
        return ResponseResult.auto(result.getStateCode(),result.getReturnData());
    }


    /**
     * 用户对购买的商品进行评价
     * @param session 购买的用户所登录的会话
     * @param evaluationInfo 评价的信息
     * @return 返回评价后的评价浏览信息
     */
    @PostMapping(value = "/evaluation/save",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResponseResult<EvaluationBrowseInfo> evaluation(HttpSession session, @Validated @NotNull EvaluationInfoParam evaluationInfo, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            return ResponseResult.failure(ServiceStateCode.PARAMETER_NONSTANDARD);
        }
        User user = (User) session.getAttribute(SessionAttributeKey.NOW_LOGIN_USER.getKey());
        ServiceReturn<EvaluationBrowseInfo> result = evaluationService.saveEvaluation(user,evaluationInfo);
        return ResponseResult.auto(result.getStateCode(),result.getReturnData());
    }

    /**
     * 用户对某评价进行评论
     * @param session 进行评论的用户的会话
     * @param commentInfo 评论的信息
     * @return 返回评论后的浏览信息
     */
    @PostMapping("/evaluation/comment/save")
    public ResponseResult<Comments> comment(HttpSession session,@Validated @NotNull CommentInfoParam commentInfo, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            return ResponseResult.failure(ServiceStateCode.PARAMETER_NONSTANDARD);
        }
        User user = (User) session.getAttribute(SessionAttributeKey.NOW_LOGIN_USER.getKey());
        ServiceReturn<Comments> result = evaluationService.saveComment(user,commentInfo);
        return ResponseResult.auto(result.getStateCode(),result.getReturnData());
    }

    /**
     * 在某评价里对某人的评价、评论回复评论进行回复评论
     * @param session 回复评论的用户的会话
     * @param replyCommentInfo 回复评论信息
     * @return 返回回复评论后的浏览信息
     */
    @PostMapping("/evaluation/replyComment/save")
    public ResponseResult<CommentsReply> replyComment(HttpSession session, @Validated @NotNull CommentReplyInfoParam replyCommentInfo, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            return ResponseResult.failure(ServiceStateCode.PARAMETER_NONSTANDARD);
        }
        User user = (User) session.getAttribute(SessionAttributeKey.NOW_LOGIN_USER.getKey());
        ServiceReturn<CommentsReply> result = evaluationService.saveReplyComment(user, replyCommentInfo);
        return ResponseResult.auto(result.getStateCode(),result.getReturnData());
    }

    /**
     * 用户浏览评价
     * @param queryParam 浏览参数
     * @return 返回评价的浏览列表
     */
    @PostMapping("/browse/evaluation")
    public ResponseResult<List<EvaluationBrowseInfo>> browseEvaluation(@Validated @NotNull EvaluationQueryParam queryParam, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            return ResponseResult.failure(ServiceStateCode.PARAMETER_NONSTANDARD);
        }
        List<EvaluationBrowseInfo> browseInfoList = browseEvaluationService.obtainBrowseList(queryParam);
        return ResponseResult.success(browseInfoList);
    }

    /**
     * 对某评价进行详细浏览
     * @param evaluationId 评价id
     * @return 返回该评价的详细信息
     */
    //保证了evaluationId不为null
    @PostMapping("/browse/evaluation/{evaluationId}")
    public ResponseResult<EvaluationDetailBrowseInfo> detailBrowseEvaluation(@PathVariable("evaluationId") Long evaluationId){
        ServiceReturn<EvaluationDetailBrowseInfo> result = browseEvaluationService.obtainDetailInfo(evaluationId);
        return  ResponseResult.auto(result.getStateCode(),result.getReturnData());
    }

    /**
     * 浏览商品
     * @param queryParam 浏览参数
     * @return 返回浏览商品的列表
     */
    @PostMapping("/browse")
    public ResponseResult<List<GoodsBrowseInfo>> browseGoods(HttpSession session,@Validated @NotNull GoodsQueryParam queryParam, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            return ResponseResult.failure(ServiceStateCode.PARAMETER_NONSTANDARD);
        }
        User user = (User) session.getAttribute(SessionAttributeKey.NOW_LOGIN_USER.getKey());
        Set<GoodsTypeFondRatio> fondRatioList = null;
        //如果当前session会话中有用户登录，则进行爱好推荐
        if(user!=null){
            //获取该用户浏览次数最多前3名的商品类型
            fondRatioList = redisClient.zsRangeByScoreDesc(RedisKey.ZRange.USER_FOND_GOODS_RECOMMEND.getKey()+user.getUserId(),0,Double.MAX_VALUE,0,3);
        }
        //获取商品的浏览列表
        ServiceReturn<List<GoodsBrowseInfo>> result = browseGoodsService.obtainBrowseList(queryParam, fondRatioList);
        return ResponseResult.auto(result.getStateCode(),result.getReturnData());
    }

    /**
     * 详细浏览指定的商品
     * @param goodsId 商品id
     * @return 返回指定商品的详细信息
     */
    //保证了goodsId不为null
    @PostMapping("/browse/{goodsId}")
    public ResponseResult<GoodsDetailBrowseInfoView> detailBrowseGoods(HttpSession session, @PathVariable("goodsId") Long goodsId){
        try {
            //异步执行，查询服务
            Future<ServiceReturn<GoodsDetailBrowseInfo>> browseGoodsServiceFuture = CachedThreadPoolUtil.submit(() ->{
               try{
                   ServiceReturn<GoodsDetailBrowseInfo> result = this.browseGoodsService.obtainDetailInfo(goodsId);
                   return result;
               }catch (Exception e){
                   e.printStackTrace();
               }
                return null;
            });
            User user = (User) session.getAttribute(SessionAttributeKey.NOW_LOGIN_USER.getKey());
            //检测该商品是否被该用户收藏
            ServiceReturn<Boolean> collectionStateResult = goodsCollectionService.checkCollectionState(user, goodsId);
            //注意：get会阻塞
            //等待查询服务的完成
            ServiceReturn<GoodsDetailBrowseInfo> result = browseGoodsServiceFuture.get();
            CachedThreadPoolUtil.submit(()->{
                if(result.getStateCode().equals(ServiceStateCode.SUCCESS)){
                    //添加到该用户的浏览历史里
                    browsingHistoryService.addUserBrowsingHistory(user,goodsId);
                }
            });
            List<StateCode> responseState = Arrays.asList(result.getStateCode(), collectionStateResult.getStateCode());
            //生成用户的详细浏览商品数据页
            GoodsDetailBrowseInfoView responseData = new GoodsDetailBrowseInfoView(result.getReturnData(), collectionStateResult.getReturnData());
            return ResponseResult.auto(responseState,responseData);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResponseResult.failure(ServiceStateCode.FAILURE);
    }

}

